import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import Axios from './custom';
import 'reflect-metadata';
import { ElMessage } from 'element-plus';
import { ResCode } from '@/enum/resCodeEnum';

const http = new Axios({
  baseURL: import.meta.env.VITE_BASE_URL,
  timeout: 100000,
});

type Method = 'GET' | 'POST' | 'PUT' | 'DELETE';

// 元数据键名
const RESPONSE_KEY = Symbol('response');
const PARAMS_KEY = Symbol('params');

// 发送 HTTP 请求的装饰器
function httpRequest(method: Method, url: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = async function (...args: any[]) {
      const paramsIndex = Reflect.getMetadata(PARAMS_KEY, target, propertyKey);
      const resultIndex = Reflect.getMetadata(RESPONSE_KEY, target, propertyKey);

      // 处理请求参数
      const config: AxiosRequestConfig = {
        method,
        url,
        [method === 'GET' ? 'params' : 'data']: args[paramsIndex] ?? {},
      };

      try {
        // 发送请求
        const response = (await http.request(config)) as AxiosResponse & AxiosError;
        // 返回响应的数据部分
        if (response.status >= 200 && response.status < 300) {
          args[resultIndex] = response.data;
        } else {
          args[resultIndex] = { code: ResCode.ERROR, message: response.message };
        }

        return originalMethod.call(target, ...args);
      } catch (error) {
        // 错误处理
        const errorMessage = error instanceof Error ? error?.message : 'Unknown error';
        throw new Error(`Failed to ${method} ${url}: ${errorMessage}`);
      }
    };
  };
}

// 处理响应数据的装饰器,保存响应数据部分的索引
const Result = (target: Object, propertyKey: string | symbol, index: number) => {
  Reflect.defineMetadata(RESPONSE_KEY, index, target, propertyKey);
};

// 处理请求参数的装饰器，保存请求参数部分的索引
const Params = (target: Object, propertyKey: string | symbol, index: number) => {
  Reflect.defineMetadata(PARAMS_KEY, index, target, propertyKey);
};

// 简化装饰器，为 GET 和 POST 创建快捷方式
const httpMethodFactory = (method: Method) => (url: string) => httpRequest(method, url);
const GET = httpMethodFactory('GET');
const POST = httpMethodFactory('POST');
const PUT = httpMethodFactory('PUT');
const DELETE = httpMethodFactory('DELETE');

// todo 上传文件,单独封装一个装饰器，后续补充进度条等功能
function UPLOAD(url: string) {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = async function (...args: any[]) {
      const paramsIndex = Reflect.getMetadata(PARAMS_KEY, target, propertyKey);
      const resultIndex = Reflect.getMetadata(RESPONSE_KEY, target, propertyKey);

      // 上传文件时，请求参数是要上传的文件
      const params = args[paramsIndex];

      if (args.length > 0 && params?.file instanceof File) {
        const formData = new FormData();
        Object.keys(params).forEach((key) => {
          formData.append(key, params[key]);
        });

        const config: AxiosRequestConfig = {
          method: 'POST',
          url,
          headers: {
            'Content-Type': 'multipart/form-data',
          },
          data: formData,
        };

        try {
          const response = (await http.request(config)) as Record<string, any>;

          // 返回响应的数据部分
          args[resultIndex] = response.data;

          return originalMethod.call(this, ...args);
        } catch (error) {
          const errorMessage = error instanceof Error ? error.message : 'Unknown error';
          throw new Error(`Failed to upload ${url}: ${errorMessage}`);
        }
      } else {
        // 如果没有提供文件，则直接调用原始方法
        return originalMethod.apply(this, args);
      }
    };
  };
}

export { http, GET, POST, PUT, DELETE, UPLOAD, Result, Params };
